package bsh.dyn;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import bsh.CompilationState;
import bsh.CompiledScript;
import bsh.exception.CompilationFailedException;
import bsh.meta.JavaClassWrapper;
import bsh.meta.TypeWrapper;

/**
 * Transformation that actually doesn't do anything, but to 'see' the type as one of its superclass or interface
 * 
 * @author takeshi
 */
public class IdentityTransformation implements Transformation, CompilableTransformation {

    private final ActualParameter theType;

    /**
     * C'tor
     * 
     * @param theType the {@link ActualParameter}
     */
    public IdentityTransformation(ActualParameter theType) {
        super();
        this.theType = theType;
    }

    /**
     * {@inheritDoc}
     */
    public ActualParameter getTransformationTarget() {
        return this.theType;
    }

    /**
     * {@inheritDoc}
     */
    public boolean acceptsType(ActualParameter parameter) {
        return theType.isSuperClassOf(parameter);
    }

    /**
     * {@inheritDoc}
     */
    public Object transform(Object object, CompiledScript script) {
        return object;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isCompilable() {
        return true;
    }

    /**
     * {@inheritDoc}
     */
    public void compile(MethodVisitor visitor, CompilationState state) throws CompilationFailedException {
        TypeWrapper targetType = JavaClassWrapper.wrapperFor(this.theType.getJavaType());
        if (!targetType.isSuperTypeOf(state.peekStack())) { // is statically proven to be of the right type. Nothing is necessary
            state.popStack();
            visitor.visitTypeInsn(Opcodes.CHECKCAST, targetType.internalName());
            state.pushStack(targetType);
        }
    }

    /**
     * {@inheritDoc}
     */
    public int getWeight() {
        return 0;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return "IdentityTransformation [theType=" + theType + "]";
    }

}